/******************************************************************************* 
  Copyright (C), 1988-2020, zeno Tech. Co., Ltd.
  Description:   VIDEO模块  
  Function List:     
  History:
    <wyg -- 2022-10-18>  创建
*******************************************************************************/ 

/*=============================================================================
                                 Includes                                  
 =============================================================================*/
#include "videoPriv.h"
#include "StreamComposeMgr.h"
#include <signal.h>
#include <sys/time.h>


/*=============================================================================
                               Macro Definition
 =============================================================================*/
#define COMPOSE_WIDTH  1920
#define COMPOSE_HEIGHT 1080
#define STREAM_OUT_NUM USBTYPEA_OUT1
#define BKG_COLOR  0xa0404040
const int Dymic_Mirror_Num = 97;
const int Digital_Signage_Num = 99;

const char*  ImgPath = "/user/data/StreamFile/PictureFile/defaultImg.yuv";
#define BACKGROUND_WIDTH  1280
#define BACKGROUND_HEIGHT 720


/*=============================================================================
                        Local Structures and Typedef 
 =============================================================================*/


/*=============================================================================
                             Extern Variables                                  
=============================================================================*/
extern int ENC_ImageBufToEnc(ENC_ctl_t *pEncCtl, MEDIA_BUFFER SrcMb,  ENC_ImageRect_t stSrcRect);

extern int VI_GetFullFromList(VI_ctl_t *pViCtl, COMM_ListInfo_t* pListPacket);

extern int VI_PutEmptyToList(VI_ctl_t *pViCtl, COMM_ListInfo_t* pListPacket);
/*=============================================================================
                             Local Variables                                  
 =============================================================================*/
static pthread_t    dataComposeThd_s[STREAM_OUT_NUM];

static pthread_t    dataPrepareThd_s;
static pthread_t    composeCheckThd_s;

static OSD_Info_t osdStream_s = {0};

static VideoTitle oldVideoTitle_s;

// 延时初始化
static long long _tick[STREAM_OUT_NUM] = {0}; 
static long long _tickErr[STREAM_OUT_NUM] = {0};

///背景图
static unsigned char *pYuvData_s = NULL;
static uint64_t yuvLen_s = 0;
static uint8_t yuvInit_s = 0;


/*=============================================================================
                             Function Definition                                  
 =============================================================================*/ 
static __inline unsigned long long GetMicroTickCount()
{
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return ((unsigned long long)ts.tv_sec * 1000000L + ts.tv_nsec / 1000);
}

static unsigned long long GetMicroTime()
{
    return GetMicroTickCount();/* us */
}

static void DelayUs(long int us)
{
    struct timeval tv;
    tv.tv_sec = us / 1000000;
    tv.tv_usec = us % 1000000;
    select(0, NULL, NULL, NULL, &tv);
}

// 每次延时一半时差,直至延时满us或差值小于err,注意要放在循环开始
static void Compose_PreciseDelay(StreamOutInterface index, long long us, long long err)
{
    if(index < STREAM_OUT_NUM)                
    {
        do
        {        
            _tickErr[index] = GetMicroTime() - _tick[index];    
            if (_tickErr[index] > 0 && us > _tickErr[index]) 
            {                                  
                _tickErr[index] = us - _tickErr[index];      
                if (_tickErr[index] > err)            
                {                              
                    DelayUs(_tickErr[index] / 2);
                    continue;                  
                }                              
            }
            break;
        }while(1);
        _tick[index] = GetMicroTime();      
    } 
}

static int Compose_SetOsdTitle(VideoTitle *pTitle, SDL_Color osdCol)
{
    int s32Ret=0, result;
    VideoTitle *pOldTitle;
    BITMAP_S stBitmap = {0};
    int s32FontSize;
    int bpp = 0, oldbpp = 0;
    int enOsdMirror = 0;

    bpp         = pTitle->bpp & 0x0f;
    enOsdMirror = pTitle->bpp & 0x10;

    if (pTitle->index > 1)
    {
        LOG_PrintError("OSD title index (%d) is out of range\n",
                       pTitle->index);
        return -1;
    }

    if (pTitle->enable)
    {
        if ((0 != bpp) && (1 != bpp) && (2 != bpp) && (3 != bpp) && (4 != bpp))
        {
            LOG_PrintError("OSD title bpp (%d) is not supported\n",
                          bpp);
            return -1;
        }

        if (   pTitle->width  <= 0
            || pTitle->height <= 0
            || pTitle->x      < 0 
            || pTitle->y      < 0)
        {
            LOG_PrintError("OSD title %d invalid paramenters!, pTitle->width=%d,pTitle->height=%d,pTitle->x=%d,pTitle->y=%d\n",
                        pTitle->index,pTitle->width,pTitle->height,pTitle->x,pTitle->y);
            return -1;
        }
    }

    pOldTitle = &oldVideoTitle_s;
    oldbpp    = pOldTitle->bpp & 0x0f;

    if (pTitle->enable)
    {        
        if (pOldTitle->enable)
        {
            if ((2 == oldbpp) || (3 == oldbpp) || (4 == oldbpp))
            {
                if (osdStream_s.logoInfo.pBuffer)
                {
                    BMP_Release(&osdStream_s.logoInfo);
                    osdStream_s.logoInfo.pBuffer = NULL;
                }
            }
        }
        if (2 == bpp)
        {
            s32FontSize = pTitle->width;//32
            ENC_StringToBmp(pTitle->data, &stBitmap, s32FontSize, osdCol);
            
            //ENC_StringToBmpV2(pTitle->data, &stBitmap, s32FontSize, BKG_COLOR);
            if(enOsdMirror)
            {
                ENC_Rgb8888Mirror(&stBitmap);
            }

            if (osdStream_s.logoInfo.pBuffer)
            {
                BMP_Release(&osdStream_s.logoInfo);
                osdStream_s.logoInfo.pBuffer = NULL;
            }

            int ret = ENC_Rgb8888ToYUV(&osdStream_s.logoInfo, &stBitmap);
            if(ret)
            {
                LOG_PrintError("ENC_Rgb8888ToYUV failed\n");
            }
            
        }
        else if (3 == bpp)
        {
            unsigned char *pData = (unsigned char *)ENC_ReadBmpFile(pTitle->data);
            if (!pData)
            {
                LOG_PrintError("Fail to read bmp file!\n"); 
                s32Ret = -1;
                goto mutex_unlock;
            }

            if (osdStream_s.logoInfo.pBuffer)
            {
                BMP_Release(&osdStream_s.logoInfo);
                osdStream_s.logoInfo.pBuffer = NULL;
            }

            result = BMP_Format(&osdStream_s.logoInfo, pData, BMP_TO_YUV420SP);
            if (result)
            {
                LOG_PrintError("Fail to format bmp!\n"); 
                free(pData);
                s32Ret = -1;
                goto mutex_unlock;
            }
        }
        else if (4 == bpp)
        {
            if (osdStream_s.logoInfo.pBuffer)
            {
                BMP_Release(&osdStream_s.logoInfo);
                osdStream_s.logoInfo.pBuffer = NULL;
            }
            ENC_StringToNV12(pTitle->data, &osdStream_s.logoInfo);//mirror todo
        }
        else
        {
            LOG_PrintError("bpp is invalid(%d)\n", bpp); 
            s32Ret = -1;
            goto mutex_unlock;
        }

        //osdStream_s.streamType = OSD_STREAM;
        //osdStream_s.storePts = vdo_get_time();


     }
     else 
     {
        if (pOldTitle->enable)
        { 
            if ((2 == oldbpp) || (3 == oldbpp) || (4 == oldbpp) )
            {
                if (osdStream_s.logoInfo.pBuffer)
                {
                    BMP_Release(&osdStream_s.logoInfo);
                    osdStream_s.logoInfo.pBuffer = NULL;
                }
            }
        }
     }

     memcpy(pOldTitle, pTitle, sizeof(VideoTitle));

mutex_unlock:
    if (NULL != stBitmap.pData)
    {
        free(stBitmap.pData);
        //LOG_PrintInfo("free stBitmap\n");
    }


    return s32Ret;
}

static int Compose_SetOsdInfo(char* osdData, short frontSize, SDL_Color osdCol)
{
    ///test
    VideoTitle title;
    title.index = 0;
    title.bpp = 2;
    title.x = 100;
    title.y = 100;
    title.width = frontSize;
    title.height = 500;
    title.enable = 1;


    title.data = (uchar*)malloc((strlen(osdData))*sizeof(char) + 1);
    strcpy((char*)title.data, osdData); //中文UTF8格式

    int ret = Compose_SetOsdTitle(&title, osdCol);

    free(title.data);

    return ret;
}


int Compose_YuvComposeOsd(MEDIA_BUFFER dstMb, int dstWidth, int dstHeight, int startX, int startY)
{
    int srcOsdW, srcOsdH;
    unsigned char *pOsdBuf = NULL;
    int osdX = 128, osdY = 128;

    osdX = startX;
    osdY = startY;
    osdX = VIDEO_ALIGN_DOWN(osdX, 4);
    osdY = VIDEO_ALIGN_DOWN(osdY, 4);

    pOsdBuf = osdStream_s.logoInfo.pBuffer;
    srcOsdW = osdStream_s.logoInfo.stride;
    srcOsdH = osdStream_s.logoInfo.height;

    if(!pOsdBuf)
    {
        printf("osdStream_s.logoInfo.pBuffer is NULL\n");
        return -1;
    }

    RK_MPI_MB_BeginCPUAccess(dstMb, RK_FALSE);
    ENC_CombineYuv(pOsdBuf, srcOsdW, srcOsdH, 
            (unsigned char*)RK_MPI_MB_GetPtr(dstMb),
            dstWidth, dstHeight, osdX, osdY);
    RK_MPI_MB_EndCPUAccess(dstMb, RK_FALSE);
    return 0;
}

static int Compose_SetNodeToList(int channel, STREAM_composeInfo_t* pNodeFrame)
{
    if (!pNodeFrame)
    {
        LOG_PrintInfo("pListFrame is NULL\n");
        return -1;
    }
    
    StreamInType type = pNodeFrame->streamType;
    if(type == HDMIIN_STREAM)
    {
        VI_ctl_t * pViCtl = videoCtl_g.pViCtl[0];
        if (!pViCtl)
        {
            LOG_PrintInfo("pViCtl is NULL\n");
            return -1;
        }

        ///put node to list
        VI_PutEmptyToList(pViCtl, &pNodeFrame->listStreamFrame); 
    }
    else
    {
        DEC_ctl_t *pDecCtl = videoCtl_g.pDecCtls[channel];
        if (!pDecCtl)
        {
            LOG_PrintInfo("pDecCtl vdecChn:%d is NULL\n",channel);
            return -1;
        }
        
        ///release buf
        /*RK_MPI_MB_ReleaseBuffer(pNodeFrame->listStreamFrame.mdBuf); 
        pNodeFrame->listStreamFrame.mdBuf = NULL;*/

        ///put node to list
        COMM_ListInfo_t* pListFrame = (COMM_ListInfo_t*)pNodeFrame->listStreamFrame.revered;
        pthread_mutex_lock(&pDecCtl->bufLock);
        list_add_tail(&pListFrame->list, &pDecCtl->emptyBuf);
        pthread_mutex_unlock(&pDecCtl->bufLock); 

        if(DEBUG_PRINT && pDecCtl->vdecChn == 0)
        LOG_PrintInfo("pDecCtl vdecChn:%d put node to list\n",pDecCtl->vdecChn);
    }

    //init
    pNodeFrame->storePts = 0;
    pNodeFrame->streamType = 0;
    pNodeFrame->multiplexNums = 0;

    return 0;
}

static int Compose_GetStreamMultiplexNum(int displayChn, uint8* multiplexNums)
{
    CurtainInfo curtainInfo = { 0 };
    StreamCofigInfo configInfo = { 0 };
    VideoMixerInfo videoMixerInfo = { 0 };
    StreamInfo stream = { 0 };
    int outNum = 0;
    int totalInput = 0;
    *multiplexNums = 0;

    getCurtainLayout(&curtainInfo); //获取拼接布局
    outNum = curtainInfo.outNum;
    if (outNum <= 0)
    {
        return -1;
    }

    for (int i = 0; i < outNum; ++i)
    {
        configInfo = curtainInfo.cofigInfo[i];

        videoMixerInfo = configInfo.videoMixerInfo;
        totalInput = videoMixerInfo.totalPictures;

        for (int j = 0; j < totalInput; ++j)
        {
            stream = videoMixerInfo.videoInfo[j].videoStream;
        #ifndef MODEL_TAIL
            if(configInfo.interface == BYOM_OUT && stream.type == USBTYPEAIN_STREAM && isVideoDirectTransfer() == 0)
            {
                continue; //BYOM_OUT的usb H26X输入源不处理，上层直接转发 
            }
        #endif
        
            if (displayChn == stream.displayChn)
            {
                *multiplexNums += 1;
            }
        }
    }

    return 0;
}

static int Compose_GetNodeFromList(int channel, StreamInType type, STREAM_composeInfo_t* pNodeFrame)
{  
    int iRet = 0;    
    if(type == HDMIIN_STREAM)
    {
        VI_ctl_t * pViCtl = videoCtl_g.pViCtl[0];
        if (!pViCtl)
        {
            LOG_PrintInfo("pViCtl is NULL\n");
            return -1;
        }

        iRet = VI_GetFullFromList(pViCtl, &pNodeFrame->listStreamFrame);
        if(iRet)
        {    
            //LOG_PrintInfo("VI_GetFullFromList failed\n");
            return -1;
        }

        //memcpy(&pNodeFrame->listStreamFrame, &pListFrame, sizeof(COMM_ListInfo_t)); //浅拷贝

        pNodeFrame->storePts = pNodeFrame->listStreamFrame.pts;
        pNodeFrame->streamType = pNodeFrame->listStreamFrame.streamType;
    }
    else
    {
        DEC_ctl_t * pDecCtl = videoCtl_g.pDecCtls[channel];
        if (!pDecCtl)
        {
            LOG_PrintInfo("pDecCtl vdecChn:%d is NULL\n",channel);
            return -1;
        }

        COMM_ListInfo_t* pListFrame = NULL; 

        ///get node from list
        pthread_mutex_lock(&pDecCtl->bufLock);            
        if(!list_empty(&pDecCtl->fullBuf))
        {
            pListFrame = list_first_entry(&pDecCtl->fullBuf, COMM_ListInfo_t, list);
            list_del(&pListFrame->list);
            pthread_mutex_unlock(&pDecCtl->bufLock);
        }
        else
        {
            pthread_mutex_unlock(&pDecCtl->bufLock);
            //LOG_PrintWarn("fullBuf list is empty!\n");
            return -1;
        }

        memcpy(&pNodeFrame->listStreamFrame, pListFrame, sizeof(COMM_ListInfo_t)); //浅拷贝
        pNodeFrame->listStreamFrame.revered = pListFrame;

        pNodeFrame->storePts = pListFrame->pts;
        pNodeFrame->streamType = pListFrame->streamType;
        Compose_GetStreamMultiplexNum(channel, &pNodeFrame->multiplexNums);

        if(DEBUG_PRINT && pDecCtl->vdecChn == 0)
            LOG_PrintInfo("pDecCtl vdecChn:%d get node from list\n",pDecCtl->vdecChn);
  
    } 


    return iRet;
}

 void Compose_initComposeBuf(STREAM_composeCtl_t* pComposeCtl)
 {
     LOG_PrintInfo("Compose_initComposeBuf enter\n");
     STREAM_composeInfo_t* pListFrame = NULL; 
     for(int i = 0; i < COMPOSE_MAX_CHN_NUM; ++i)
     {
         pthread_rwlock_wrlock(&pComposeCtl->decComposeBuf[i].rwLock);
         

         pListFrame = &pComposeCtl->decComposeBuf[i];
         
         if(pListFrame->storePts > 0)
          Compose_SetNodeToList(i, pListFrame);

         pComposeCtl->newPts[i] = 0;
 
         pthread_rwlock_unlock(&pComposeCtl->decComposeBuf[i].rwLock);
     }
 
     LOG_PrintInfo("Compose_initComposeBuf leave\n");
 }

 static void *Compose_DataPrepareThd(void *parg)
 {
    STREAM_composeCtl_t* pComposeCtl = (STREAM_composeCtl_t*)parg;
    if (!pComposeCtl)
    {
        LOG_PrintInfo("pComposeCtl is NULL\n");
        return NULL;
    }

    prctl(PR_SET_NAME, __func__);
    LOG_PrintInfo("tid:%d\n", gettid());

    STREAM_composeInfo_t* pListFrame = NULL; 
    DEC_ctl_t *pDecCtl = NULL;
     
    StreamInfo streamInfo[COMPOSE_MAX_CHN_NUM];
    int streamNum = 0;
    StreamInType type = INSIDE_STREAM;
    char osdData[256] = {0};
    int streamIndex = 0;
    int isStreamUpdte = 0;
    int ret = 0;
    PlayState state = IDLE;
    PlayState lastState = IDLE;
 
    while(1)
    {
        getCurtainPlayState(&state);
        if(state != RUNNING)
        {
            if(lastState == RUNNING)
            {
                lastState = state;
                Compose_initComposeBuf(pComposeCtl);
            }
            usleep(5*1000);
            continue;
        }
        lastState = state; 

        streamNum = 0;
        getStreamInfo(0, streamInfo, &streamNum);
        if(streamNum <= 0 || streamNum >= COMPOSE_MAX_CHN_NUM)
        {
            usleep(10*1000);
            continue;
        }

        isStreamUpdte = 0;
        for(int i = 0; i < streamNum; ++i)
        {
            type = streamInfo[i].type;

            if(type == OSD_STREAM)
            {
                continue;
            }
            else
            {
                streamIndex = streamInfo[i].displayChn;
            }

            int iRet = pthread_rwlock_trywrlock(&pComposeCtl->decComposeBuf[streamIndex].rwLock);//加写锁
            if(iRet != 0)
            {
                continue;
            }
            
          
            pListFrame = &pComposeCtl->decComposeBuf[streamIndex];
            
            if(pComposeCtl->newPts[streamIndex] > pListFrame->storePts)
            {
                if(streamIndex == MIRROR_STREAM_INDEX || 
                        pComposeCtl->userNums[streamIndex] >= pListFrame->multiplexNums)
                {
                    if(pListFrame->storePts > 0)
                       Compose_SetNodeToList(streamIndex, pListFrame);				 
                       
                    Compose_GetNodeFromList(streamIndex, type, pListFrame);
                    pComposeCtl->userNums[streamIndex] = 0;
                    isStreamUpdte = 1;
                }
            }


            if(DEBUG_PRINT && i == 0)
            {
                LOG_PrintInfo("newPts[%d]=%llu, framepts=%llu\n", i, pComposeCtl->newPts[i], pListFrame->storePts);
            }

            pthread_rwlock_unlock(&pComposeCtl->decComposeBuf[streamIndex].rwLock);
        }      

        usleep(500);
        // if(isStreamUpdte == 1)
        // {
        //     usleep(300);
        // }
        // else
        // {
        //     usleep(500);
        // }
    }
     
     return NULL;
 }

#if 1

void *Compose_ReadYuvFile(unsigned char *pPath, uint64_t* length)
{
    int ret = 0;
    int fdYuv = -1;
    int fileSize = 0;
    unsigned char *pData = NULL;
    
    fdYuv = open((char *)pPath, O_RDONLY);
    if (-1 == fdYuv)
    {
        LOG_PrintError("Fail to open the image file!, pPath=%s\n", pPath);
        return NULL;
    }

    fileSize = lseek(fdYuv, 0, SEEK_END);
    if (-1 == fileSize)
    {
        LOG_PrintError("Fail to lseek the image file!\n");
        ret = -1;
        goto release;
    }

    if (lseek(fdYuv, 0, SEEK_SET) == -1)
    {
        LOG_PrintError("Fail to open the image file!\n");
        ret = -1;
        goto release;
    }

    *length = fileSize;

    pData = (unsigned char *)malloc(fileSize);
    if (!pData)
    {
        LOG_PrintError("Fail to malloc memory!\n");
        ret = -1;
        goto release;
    }

    if (read(fdYuv, pData, fileSize) <= 0)
    {
        LOG_PrintError("Fail to read the image file!\n");
        ret = -1;
        goto release;
    }

release:
    if (fdYuv != -1)
    {
        close(fdYuv);
    }

    if (ret)
    {
        return NULL;
    }
    else
    {
        return (void *)pData;
    }
}

static void Flush_MbColor(rga_buffer_t * rgaResize,
                        int x, int y, int width, int height)
{
    int sync = 1;
    int color = 0x00000000;    
    im_rect imRect = { x, y, width, height };
    
    IM_STATUS status = imfill(*rgaResize, imRect, color, sync);
    if (status != IM_STATUS_SUCCESS)
    {
        LOG_PrintError("imflip failed: %s\n", imStrError(status));
    }
}

static MEDIA_BUFFER Compose_defaultImageDeal()
{
    if(yuvInit_s == 0)
    {
        pYuvData_s = Compose_ReadYuvFile(ImgPath, &yuvLen_s);
        LOG_PrintInfo("Compose_ReadYuvFile length=%lld\n", yuvLen_s);
        yuvInit_s = 1;        
    }

    if(!pYuvData_s || yuvLen_s == 0)
    {
        LOG_PrintError("pYuvData_s is NULL !\n");
        return NULL;
    }
    
    MB_IMAGE_INFO_S displayMbInfo = {0};
    displayMbInfo.enImgType = IMAGE_TYPE_NV12;
    displayMbInfo.u32Width = BACKGROUND_WIDTH;
    displayMbInfo.u32Height = BACKGROUND_HEIGHT;
    displayMbInfo.u32HorStride = BACKGROUND_WIDTH;
    displayMbInfo.u32VerStride = BACKGROUND_HEIGHT;
    MEDIA_BUFFER stReadMb = RK_MPI_MB_CreateImageBuffer(&displayMbInfo, RK_TRUE, 0);
    if (!stReadMb)
    {
        LOG_PrintError("RK_MPI_MB_CreateBuffer failed !\n");
        return NULL;
    }


    RK_MPI_MB_BeginCPUAccess(stReadMb, RK_FALSE);
    memcpy((unsigned char*)RK_MPI_MB_GetPtr(stReadMb), pYuvData_s, yuvLen_s);
    RK_MPI_MB_EndCPUAccess(stReadMb, RK_FALSE);

    return stReadMb;
}

static void * Video_ComposeCheckThd(void* arg){
    STREAM_composeCtl_t* pComposeCtl = videoCtl_g.pComposeCtl;
    if (!pComposeCtl)
    {
        LOG_PrintInfo("pComposeCtl is NULL\n");
        return NULL;
    }
    CurtainInfo curtainInfo = {0};
    StreamCofigInfo configInfo = {0};
    PlayState state = IDLE;
    PlayState last_state = IDLE;

    while(1){
        memset(&curtainInfo, 0, sizeof(curtainInfo));
        getCurtainLayout(&curtainInfo); //获取拼接布局
        getCurtainPlayState(&state);
        if(state == last_state){
            usleep(50000);
            continue;
        }

        last_state = state;
        if(curtainInfo.outNum <= 0 || state != RUNNING)
        {
            for(int i = 0; i < COMPOSE_MAX_CHN_NUM; ++i){
                pComposeCtl->running[i] = 0;
            }
            usleep(50000);
            continue;
        }
        
        for(int i = 0; i < curtainInfo.outNum; ++i)
        {
            configInfo = curtainInfo.cofigInfo[i];
            pthread_mutex_lock(&pComposeCtl->mutex_run[configInfo.interface]);
            pthread_cond_signal(&pComposeCtl->cond_run[configInfo.interface]);
            pComposeCtl->running[configInfo.interface] = 1;
            pthread_mutex_unlock(&pComposeCtl->mutex_run[configInfo.interface]);
        }
        usleep(50000);
    }
    return NULL;
}


static void *Compose_DataComposeThd(void *parg)
{
    StreamOutInterface interface = USBTYPEC_OUT;
    memcpy(&interface, (StreamOutInterface*)parg, sizeof(StreamOutInterface));
    free(parg);

    //LOG_PrintInfo("Video Output interface=%d\n", interface);

    STREAM_composeCtl_t* pComposeCtl = videoCtl_g.pComposeCtl;
    if (!pComposeCtl)
    {
        LOG_PrintInfo("pComposeCtl is NULL\n");
        return NULL;
    }

    prctl(PR_SET_NAME, __func__);
    //LOG_PrintInfo("Compose_DataComposeThd::interface:%d, tid:%d\n", interface, gettid());
    COMM_ListInfo_t* pListFrame = NULL;

    MEDIA_BUFFER displayMb = NULL;
    rga_buffer_t *rgaDisplayPtr;
    MEDIA_BUFFER resizeMb1 = NULL;
    MEDIA_BUFFER resizeMb2 = NULL;
    MEDIA_BUFFER resizeMb3 = NULL;
    rga_buffer_t rgaResize[3];
    MB_IMAGE_INFO_S displayMbInfo = {0};
    rga_buffer_t rgaDisply;
    int curDisplyW = 0;
    int curDisplyH = 0; 
    int oldDisplyW = 0;
    int oldDisplyH = 0; 
    int curFps = 0;
    int oldFps = 0;

    ENC_ImageRect_t stSrcRect = {0};
    ENC_ImageRect_t stDstRect = {0};
    ENC_listImageBufInfo_t stImageBuffer = {0};
    MEDIA_BUFFER srcMd;

    ///resize buf
    int mbSize = COMPOSE_WIDTH * COMPOSE_HEIGHT *2;  //*3/2;
    MEDIA_BUFFER stResizeMb = RK_MPI_MB_CreateBuffer(mbSize, RK_TRUE, 0);
    if (!stResizeMb)
    {
        LOG_PrintError("RK_MPI_MB_CreateBuffer failed !\n");
        return NULL;
    }

    CurtainInfo curtainInfo = {0};
    StreamCofigInfo configInfo = {0};
    VideoMixerInfo videoMixerInfo = {0};
    StreamInfo stream = {0};
    ScreenCodt copyCodt = {0}; 
    int outNum = 0;
    ResolutionDef resolution = 0;
    
    int pictureNum = 0;
    int dealNum = 0;
    int listChn = 0;
    int displayChn = 0;
    int iRet = 0;
    int sync = 1;
    int isSavePic = 0;
    int count = 0;
    PlayState state = IDLE;
    PlayState lastState = IDLE;
    int bufIndex = 0;
    char osdData[256] = {0};
    int streamWidth = 0;
    int streamHeight = 0;
    bool streamNeedFlush = false;

    static int firstFlushFlg = 0;

    uint64 lastFramPts[COMPOSE_MAX_CHN_NUM] = {0};

    uint64 noUpdateCnt[COMPOSE_MAX_CHN_NUM] = {0};

    MEDIA_BUFFER defaultMb = NULL;

    if(interface == USBTYPEC_OUT)
    {
        defaultMb = Compose_defaultImageDeal();
        if (!defaultMb)
        {
            LOG_PrintError("Compose_defaultImageDeal defaultMb NULL !\n");
        }
    }

    uint8_t tasktimeFlg = 0;
    uint8_t noStreamCnt = 0;
    int     curtainNum = 0;
    uint8_t streamUpdateNum = 0; 
    int     lastPlayNum = -1;
    uint8_t defaultDisplay = 0;

    while(1)
    {
        pthread_mutex_lock(&pComposeCtl->mutex_run[interface]);
        if(pComposeCtl->running[interface] == 0){
            struct timespec timeout;
            clock_gettime(CLOCK_REALTIME, &timeout);
            timeout.tv_sec += 2;

            if(pthread_cond_timedwait(&pComposeCtl->cond_run[configInfo.interface], 
                &pComposeCtl->mutex_run[interface], &timeout) != 0){
                pthread_mutex_unlock(&pComposeCtl->mutex_run[interface]);
                continue;
            }    
        }
        pthread_mutex_unlock(&pComposeCtl->mutex_run[interface]);

        if(tasktimeFlg == 0)
        {
            Compose_PreciseDelay(interface,32800, 1); //32800-16000
        }
        else if(tasktimeFlg == 1)
        {
            Compose_PreciseDelay(interface,100*1000, 10);
        }
        else if (tasktimeFlg == 2) 
        {
            Compose_PreciseDelay(interface, 16000, 1);
        }

        //Compose_PreciseDelay(interface,16666, 1); //60帧
                
        /* step1: get state and layout */
        getCurtainPlayState(&state);
        if(state != RUNNING)
        {
            //LOG_PrintWarn("state: %d\n", state);

            if(lastState != RUNNING)
            {
                continue;
            }
        }

        lastState = state;

        memset(&curtainInfo, 0, sizeof(curtainInfo));
        getCurtainLayout(&curtainInfo); //获取拼接布局
        outNum = curtainInfo.outNum;
        if(outNum <= 0)
        {
            //LOG_PrintError("pictureNum is error !\n");
            continue;
        }
        curtainNum = curtainInfo.curtainNum;

        //unsigned long long ts = vdo_get_time();

        /* step2: compose picture */
        memset(&configInfo, 0, sizeof(configInfo));
        memset(&videoMixerInfo, 0, sizeof(videoMixerInfo));
        dealNum = 0;
        srcMd = NULL;
        tasktimeFlg = 0;
        streamUpdateNum = 0;
        
        for(int i = 0; i < outNum; ++i)
        {
            configInfo = curtainInfo.cofigInfo[i];
            //LOG_PrintError("configInfo.interface is %d , interface:%d!, outNum=%d, i=%d\n", configInfo.interface,interface, outNum, i);
            if(configInfo.interface != interface) //每种输出对应一个拼接线程
            {
                continue;
            }
            
            videoMixerInfo = configInfo.videoMixerInfo;
            pictureNum = videoMixerInfo.totalPictures;
            if(pictureNum <= 0)
            {
                continue;
            }
            
            curDisplyW = videoMixerInfo.displayWidth;
            curDisplyH = videoMixerInfo.displayHeight;
            curFps = videoMixerInfo.displayFps;

            displayMbInfo.enImgType = IMAGE_TYPE_NV12;
            displayMbInfo.u32Width = curDisplyW;
            displayMbInfo.u32Height = curDisplyH;
            displayMbInfo.u32HorStride = curDisplyW;
            displayMbInfo.u32VerStride = curDisplyH;

            //printf("*******Interface:%d-->curDisplyW=%d, curDisplyH=%d, pictureNum=%d\n",interface, curDisplyW, curDisplyH, pictureNum); 
            
            if(curDisplyW != oldDisplyW || curDisplyH != oldDisplyH) //
            {
                //printf("*******Interface:%d-->curDisplyW=%d, curDisplyH=%d,  oldDisplyW=%d, oldDisplyH=%d\n",interface, curDisplyW, curDisplyH, oldDisplyW,oldDisplyH); 
                if (resizeMb1)
                {
                    RK_MPI_MB_ReleaseBuffer(resizeMb1);
                    resizeMb1 = NULL;
                }                
                resizeMb1 = RK_MPI_MB_CreateImageBuffer(&displayMbInfo, RK_TRUE, 0);
                if (!resizeMb1) 
                {
                    LOG_PrintError("Fail to RK_MPI_MB_CreateImageBuffer!\n");
                    continue;
                }
                rgaResize[0] = wrapbuffer_fd(RK_MPI_MB_GetFD(resizeMb1), curDisplyW,
                                curDisplyH, RK_FORMAT_YCbCr_420_SP);

                if (resizeMb2)
                {
                    RK_MPI_MB_ReleaseBuffer(resizeMb2);
                    resizeMb2 = NULL;
                }                
                resizeMb2 = RK_MPI_MB_CreateImageBuffer(&displayMbInfo, RK_TRUE, 0);
                if (!resizeMb2) 
                {
                    LOG_PrintError("Fail to RK_MPI_MB_CreateImageBuffer!\n");
                    continue;
                }
                rgaResize[1] = wrapbuffer_fd(RK_MPI_MB_GetFD(resizeMb2), curDisplyW,
                                curDisplyH, RK_FORMAT_YCbCr_420_SP);

                if (resizeMb3)
                {
                    RK_MPI_MB_ReleaseBuffer(resizeMb3);
                    resizeMb3 = NULL;
                }                
                resizeMb3 = RK_MPI_MB_CreateImageBuffer(&displayMbInfo, RK_TRUE, 0);
                if (!resizeMb3) 
                {
                    LOG_PrintError("Fail to RK_MPI_MB_CreateImageBuffer!\n");
                    continue;
                }
                rgaResize[2] = wrapbuffer_fd(RK_MPI_MB_GetFD(resizeMb3), curDisplyW,
                                curDisplyH, RK_FORMAT_YCbCr_420_SP);
                
                oldDisplyW = displayMbInfo.u32Width;
                oldDisplyH = displayMbInfo.u32Height;

                if(firstFlushFlg == 1)
                {
                    firstFlushFlg = 0;
                }
            }

            /* 3块buffer交替使用，解决HDMIOUT闪屏问题 */          
            if(0 == count)
            {
                displayMb = resizeMb1;
                rgaDisplayPtr = &rgaResize[0];
                count = 1;
            }
            else if(1 == count)
            {
                displayMb = resizeMb2;
                rgaDisplayPtr = &rgaResize[1];
                count = 2;
            }
            else
            {
                displayMb = resizeMb3;
                rgaDisplayPtr = &rgaResize[2];
                count = 0;
            }

            
    #if 1
            //state != RUNNING
            if(firstFlushFlg == 0)
            {
                ///TEST FILL
                for (int i = 0; i < 3; ++i)
                {
                    Flush_MbColor(&rgaResize[i], 0, 0, curDisplyW, curDisplyH);
                }
                LOG_PrintWarn("state: %d, laststate:%d, firstFlushFlg:%d\n", state, lastState, firstFlushFlg);

                if(firstFlushFlg == 0)
                {
                    firstFlushFlg = 1;
                }
                else
                {
                #if 0
                    dealNum = 1; 
                    
                    stDstRect.wid = curDisplyW;
                    stDstRect.hei = curDisplyH;
                    stDstRect.wstride = curDisplyW;
                    stDstRect.hstride = curDisplyH;
                #endif
                    break;
                }
            }
    #endif 
            else
            {
                //unsigned long long ts = vdo_get_time();
            
        #if 1
                /* step3: compose picture */
                for(int j = 0; j < pictureNum; ++j)
                {
                    stream = videoMixerInfo.videoInfo[j].videoStream;
                    copyCodt = videoMixerInfo.videoInfo[j].codt;
                    displayChn = stream.displayChn;
                    if(displayChn >= COMPOSE_MAX_CHN_NUM 
                        || copyCodt.width == 0
                        || copyCodt.height == 0)
                    {
                        //LOG_PrintError("displayChn is over !\n");
                        continue;
                    }           

                    StreamInType type = stream.type;
                #ifndef MODEL_TAIL
                    if((interface == BYOM_OUT && type == USBTYPEAIN_STREAM && isVideoDirectTransfer() == 0)
                      || (type == INSIDE_STREAM))
                    {
                        continue; // BYOM_OUT的usb H26X输入源不处理，上层直接转发;INSIDE_STREAM流不处理  
                    }
                #endif
                
                    if(type == OSD_STREAM)
                    {
                        continue;
                    }
                    else
                    {  
                        bufIndex = displayChn;
                        
                        pthread_rwlock_rdlock(&pComposeCtl->decComposeBuf[bufIndex].rwLock); //加读锁
                       
                        pListFrame = &pComposeCtl->decComposeBuf[bufIndex].listStreamFrame;

                        // LOG_PrintWarn("!!!!!!!!!!! DataCompose bufIndex  %d,  pts %llu\n", bufIndex, pListFrame->pts);
                        if((pListFrame->pts == 0) || (pComposeCtl->decComposeBuf[bufIndex].storePts == 0) || (pComposeCtl->newPts[bufIndex] == 0))
                        {
                            pthread_rwlock_unlock(&pComposeCtl->decComposeBuf[bufIndex].rwLock);
                            //LOG_PrintWarn("test return\n");
                            /*Flush_MbColor(rgaDisplayPtr, VIDEO_ALIGN_DOWN(copyCodt.left, 2), 
                                VIDEO_ALIGN_DOWN(copyCodt.top, 2), VIDEO_ALIGN_DOWN(copyCodt.width, 4), VIDEO_ALIGN_DOWN(copyCodt.height, 2));*/
                            continue;
                        }
                        if(pListFrame->pts == lastFramPts[bufIndex])
                        {                             
                            if((noUpdateCnt[bufIndex]) == 60) //do while
                            {                                
                                if(type != PICTUREFILE_STREAM 
                                  && type != MIRROR_STREAM
                                  && type != ONLINEMP4_STREAM
                                  && type != VIDEOFILE_STREAM)
                                {
                                    pthread_rwlock_unlock(&pComposeCtl->decComposeBuf[bufIndex].rwLock);
                                    Flush_MbColor(rgaDisplayPtr, VIDEO_ALIGN_DOWN(copyCodt.left, 2), 
                                        VIDEO_ALIGN_DOWN(copyCodt.top, 2), VIDEO_ALIGN_DOWN(copyCodt.width, 4),VIDEO_ALIGN_DOWN(copyCodt.height, 2));
                                    continue;
                                }
                            }
                            else
                            {
                                noUpdateCnt[bufIndex] += 1;
                                tasktimeFlg = 2;
                                //pthread_rwlock_unlock(&pComposeCtl->decComposeBuf[bufIndex].rwLock);
                                // continue;

                                if(interface == BYOM_OUT){
                                    pthread_rwlock_unlock(&pComposeCtl->decComposeBuf[bufIndex].rwLock);
                                    continue;
                                }
                            }
                            
                        }
                        else
                        {
                            noUpdateCnt[bufIndex] = 0;
                            streamUpdateNum++;
                        }
                        

                        lastFramPts[displayChn] = pListFrame->pts;
                        

                        if(pListFrame->isNocopy == 1)
                        {
                            srcMd = pListFrame->mdBuf;
                        }
                        else
                        {
                            srcMd = pListFrame->mdResizeBuf;
                        } 
                        if(srcMd == NULL)
                        {
                            LOG_PrintError("pListFrame  mdBuf is NULL !\n"); 
                            pthread_rwlock_unlock(&pComposeCtl->decComposeBuf[bufIndex].rwLock);
                            continue;
                        }
                        
                        memcpy(&stSrcRect, &(pListFrame->stImageInfo), sizeof(ENC_ImageRect_t));
                        memset(&stDstRect ,0x0,sizeof(ENC_ImageRect_t));
                        
                        if (streamWidth != stSrcRect.wid || streamHeight != stSrcRect.hei) {
                            streamWidth = stSrcRect.wid;
                            streamHeight = stSrcRect.hei;
                            streamNeedFlush = true;
                        }

                        if((stSrcRect.wid != copyCodt.width) || (stSrcRect.hei != copyCodt.height))
                        {     
                            if (pictureNum == 1 && (type == ONLINEMP4_STREAM || type == MIRROR_STREAM || type == VIDEOFILE_STREAM)) {
                                copyCodt.left = (COMPOSE_WIDTH - stSrcRect.wid) / 2;
                                copyCodt.top = (COMPOSE_HEIGHT - stSrcRect.hei) / 2;
                                copyCodt.width = stSrcRect.wid;
                                copyCodt.height = stSrcRect.hei;
                                
                                //flush back pic to black
                                if (streamNeedFlush) {
                                    streamNeedFlush = false;
                                    for (int i = 0; i < 3; ++i)
                                    {
                                        Flush_MbColor(&rgaResize[i], 0, 0, curDisplyW, curDisplyH);
                                    }
                                }
                            }
                            else {
                                ///图像resize
                                stDstRect.wid = copyCodt.width;
                                stDstRect.hei = copyCodt.height;
                                stDstRect.wstride = stDstRect.wid;
                                stDstRect.hstride = stDstRect.hei;


                                iRet = VI_ImageResizeRga(stSrcRect, stDstRect, srcMd, stResizeMb, RK_FORMAT_YCbCr_420_SP, RK_FORMAT_YCbCr_420_SP);
                                if(iRet < 0)
                                {
                                    LOG_PrintError("VI_ImageResizeRga failed !\n"); 
                                    pthread_rwlock_unlock(&pComposeCtl->decComposeBuf[bufIndex].rwLock);
                                    continue;
                                }

                                srcMd = stResizeMb;

                                stSrcRect = stDstRect;
                            }
                        }

                        stDstRect.wid = curDisplyW;
                        stDstRect.hei = curDisplyH;
                        stDstRect.wstride = curDisplyW;
                        stDstRect.hstride = curDisplyH;
                        
                        //srcBuf = wrapbuffer_fd(RK_MPI_MB_GetFD(srcMd), copyCodt.width, copyCodt.height, RK_FORMAT_YCbCr_420_SP);

                        ///图像合成
                        im_rect stSrcImRect = {0};
                        stSrcImRect.x      = 0;
                        stSrcImRect.y      = 0;
                        stSrcImRect.width  = copyCodt.width;
                        stSrcImRect.height = copyCodt.height;

                        im_rect stPatImRect = {0};
                        ENC_ImageRect_t stPatRect = {0};

                        im_rect stDstImRect = {0};
                        stDstImRect.x      = copyCodt.left;
                        stDstImRect.y      = copyCodt.top;
                        stDstImRect.width  = copyCodt.width;
                        stDstImRect.height = copyCodt.height;

                        iRet = VI_ImageResizeImprocess(stSrcRect, stDstRect, stDstRect, stSrcImRect, stDstImRect, stDstImRect, srcMd, displayMb, displayMb, IM_ALPHA_BLEND_SRC);//IM_ALPHA_BLEND_SRC_OVER
                        pthread_rwlock_unlock(&pComposeCtl->decComposeBuf[bufIndex].rwLock);

                        if(noUpdateCnt[bufIndex] == 0)//流有更新才修改计数
                        {
                            pthread_rwlock_wrlock(&pComposeCtl->decComposeBuf[displayChn].rwLock); //加写锁
                            pComposeCtl->userNums[displayChn] += 1;
                            pthread_rwlock_unlock(&pComposeCtl->decComposeBuf[displayChn].rwLock);

                            //LOG_PrintError("interface=%d, userNums=%d\n", interface, pComposeCtl->userNums[displayChn] ); 
                        }
                        if (iRet < 0)
                        { 
                            LOG_PrintError("VI_ImageResizeImprocess failed !\n"); 
                            continue;
                        }

                    }

                    dealNum++;
                    
                }

                /*if(interface == 0)
                {
                    unsigned long long  runtime = vdo_get_time() - ts;
                    printf("Compose_DataComposeThd::VI_ImageResizeImprocess runtime=%llu, interface=%d\n",runtime, interface);
                }*/
                
             #endif
             break;
            }

        }

        if(pictureNum > 1 && dealNum > 0 && streamUpdateNum > 0)
        {
            tasktimeFlg = 0; //多路拼接时有流更新循环时间恢复   
        }

        defaultDisplay = 0;
        if((interface == USBTYPEC_OUT || interface == HDMI_OUT)
          && (dealNum == 0))
        {
            if(interface == HDMI_OUT && (curtainNum == Dymic_Mirror_Num || curtainNum == Digital_Signage_Num))
            {
                lastPlayNum = curtainNum;
                continue;
            }

            //场景持续无数据或切换到默认场景，才展示底图
            if(((lastPlayNum != curtainNum) && (curtainNum == 107 || curtainNum == 106))
              || (noStreamCnt == VIDEO_SHOW_OSD_PICTURE_TIME))
            {
                if(interface == HDMI_OUT)
                {
                  #ifndef MODEL_TAIL
                    DisplayDefaultDigitalSignage(); //GUI发送底图
                  #endif
                }
                else if(interface == USBTYPEC_OUT)
                {
                    if(defaultMb)
                    {
                        displayMb = defaultMb; 

                        stDstRect.wid = BACKGROUND_WIDTH;
                        stDstRect.hei = BACKGROUND_HEIGHT;
                        stDstRect.wstride = BACKGROUND_WIDTH;
                        stDstRect.hstride = BACKGROUND_HEIGHT;

                        dealNum = 1; //普通发送
                    }
                }
                
                lastPlayNum = curtainNum;                     
                tasktimeFlg = 1;
                defaultDisplay = 1;
            }
            else
            {
                noStreamCnt++;
            }
        }
        else
        {
            noStreamCnt = 0;
        }

         /* step4: send Image to all list */
        if(dealNum > 0)
        {
            if (!sync)
            {
                imsync();
            }

            if(interface == BYOM_OUT){
                // printf("  ### compose  byom  pts %llu\n", pListFrame->pts);
                RK_MPI_MB_SetTimestamp(displayMb, pListFrame->pts);
            }else{
                RK_MPI_MB_SetTimestamp(displayMb, vdo_get_time());
            }


            MB_IMAGE_INFO_S stImageInfo = {0};
            RK_MPI_MB_GetImageInfo(displayMb, &stImageInfo);
            /*LOG_PrintWarn("RK_MPI_SYS_GetMediaBuffer ImgInfo:<wxh %dx%d, fmt 0x%x>, HorStride:%d, VerStride:%d, pVir:%p\n",
                         stImageInfo.u32Width,
                         stImageInfo.u32Height, 
                         stImageInfo.enImgType,
                         stImageInfo.u32HorStride,
                         stImageInfo.u32VerStride,
                         RK_MPI_MB_GetPtr(displayMb));*/

            if(1 == isSavePic)
            {
                static int cnt = 0;
                char path[64];
                sprintf(path,"/nfsroot/wyg/image_list_%d.yuv",cnt);
                int size = RK_MPI_MB_GetSize(displayMb);
                void* pVir = RK_MPI_MB_GetPtr(displayMb);
                vdo_writeToFile(path,size,pVir);

                if(cnt++ > 10)
                {
                    cnt = 0;
                    isSavePic = 0;
                }
            }

            if(interface == HDMI_OUT)
            {
                if(1 == HdmiIsEnable())
                {
                    if (defaultDisplay == 0) //默认底图不显示情况下显示osd简化信息
                    {   
                        #ifndef MODEL_TAIL
                            DisplayOsd();
                        #endif
                    }

                    int ret = RK_MPI_SYS_SendMediaBuffer(RK_ID_VO, 0, displayMb);
                    if (ret) 
                    {
                        LOG_PrintError("RK_MPI_SYS_SendMediaBuffer to VO[0] failed! ret=%d\n",ret);
                    }
                }
            }
            else
            {
                ENC_ctl_t *pEncCtl = videoCtl_g.pEncCtls[interface];
                if (!pEncCtl || (stDstRect.hei <= 0) || (stDstRect.wid <= 0) )
                { 
                    continue;
                }
                //LOG_PrintError("Interface=%d, stSrcRect.wid=%d, stSrcRect.hei=%d,pEncCtl->encState=%d\n", interface, stDstRect.wid, stDstRect.hei, pEncCtl->encState); 

                ENC_ImageBufToEnc(pEncCtl, displayMb, stDstRect);                
            }
            
        #if 0
            unsigned long long  runtime = vdo_get_time() - ts;
            printf("Compose_DataComposeThd::dealPacket runtime=%llu, interface=%d\n",runtime, interface);
        #endif
            
        }    
    }
    return NULL;   
}

#endif

 /// 创建视频解码接口。创建成功后，如果芯片资源限制，不一定可以正常解码。
 /// 
 /// \param [in] dest 视频解码接口描述结构VideoDecDesc指针
 /// \param [out] videoDecoder 视频解码接口指针的指针
 /// \retval <0 创建失败
 /// \retval 0 创建成功
 int Compose_InitStreamCompose()
 {
    int ret = 0;
    int  i = 0;

    STREAM_composeCtl_t* pComposeCtl = NULL;

    pthread_mutex_lock(&videoCtl_g.composeMutex);
    

    pComposeCtl = videoCtl_g.pComposeCtl;
    if (pComposeCtl)
    {
        LOG_PrintInfo("stream compose has already been created\n");
        goto mutex_unlock;
    }

    pComposeCtl = (STREAM_composeCtl_t *)malloc(sizeof(STREAM_composeCtl_t));
    if (!pComposeCtl)
    {
        LOG_PrintError("There is no enough memory to allocate STREAM_composeCtl_t!\n");
        ret = -1;
        goto mutex_unlock;
    }
    memset(pComposeCtl, 0, sizeof(STREAM_composeCtl_t));

    for(i = 0; i < COMPOSE_MAX_CHN_NUM; ++i)
    {
        pComposeCtl->userNums[i] = 0;
        pComposeCtl->decComposeBuf[i].multiplexNums = 0;
        pthread_rwlock_init(&pComposeCtl->decComposeBuf[i].rwLock, NULL);     

        pthread_mutex_init(&pComposeCtl->mutex_run[i], NULL);
        pthread_cond_init(&pComposeCtl->cond_run[i], NULL);
    }
    
#if 1
    /* create send thread */
    ret = pthread_create(&dataPrepareThd_s, NULL, Compose_DataPrepareThd, pComposeCtl);
    if(ret)
    {
        LOG_PrintError("can't create thread: %s\n", strerror(ret));
        ret = -1;
    }
#endif

    videoCtl_g.pComposeCtl = pComposeCtl;

#if 1
    /* create send thread */    
    for(i = 0; i < STREAM_OUT_NUM; ++i)
    {
        if(i == RTSP_SUB_OUT1 || i == RTSP_SUB_OUT2 || i == RTSP_SUB_OUT3 || i == RTSP_SUB_OUT4 ||
            i == RTSP_SUB_OUT5){
                continue;
        }

        StreamOutInterface *pInterface = malloc(sizeof(*pInterface));
        if(!pInterface)
        {
            LOG_PrintError("malloc failed\n");
            continue;
        }
        
        *pInterface = i;   
        ret = pthread_create(&dataComposeThd_s[i], NULL, Compose_DataComposeThd, (void*)pInterface);
        if(ret)
        {
            LOG_PrintError("can't create thread: %s\n", strerror(ret));
            ret = -1;
        }
    }
#endif
    
    pthread_create(&composeCheckThd_s,NULL,Video_ComposeCheckThd,NULL);
    LOG_PrintInfo("initStreamComposesuccessfully!\n");


mutex_unlock:
    pthread_mutex_unlock(&videoCtl_g.composeMutex);


    return ret;
 }

